﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using QuailDashboard.View.Data;
using QuailDashboard.View.Helpers;

namespace QuailDashboard.View.Controls
{
    /// <summary>
    /// helps show Hierarchal data into a treeview
    /// </summary>
    public class HierarchalTreeView : TreeView
    {
        private IHierarchalData _pendingSelect;
        private bool _selectFoundItem;

        /// <summary>
        /// Initializes a new instance of the <see cref="HierarchalTreeView"/> class.
        /// </summary>
        public HierarchalTreeView()
        {
            LayoutUpdated += Control_LayoutUpdated;
            this.AttachMouseScrolling();
        }

        /// <summary>
        /// Delegate when FindTreeViewItem is finished
        /// </summary>
        /// <param name="sender">this control</param>
        /// <param name="tvitem">the found treeview item (or null if it was not found)</param>
        /// <param name="data">the data it was looking for</param>
        public delegate void OnFindTreeVewItem(object sender, HierarchalTreeViewItem tvitem, IHierarchalData data);

        /// <summary>
        /// Fired when FindTreeViewItem is complete
        /// </summary>
        public event OnFindTreeVewItem FindTreeVewItemComplete;

        /// <summary>
        /// Looks for a treeview item, firing FindTreeVewItemComplete when the item is found or the find is complete
        /// </summary>
        /// <param name="data">the data to look for</param>
        public void FindTreeViewItem(IHierarchalData data)
        {
            FindTreeViewItem(data, true);
        }

        /// <summary>
        /// Looks for a treeview item, firing FindTreeVewItemComplete when the item is found or the find is complete
        /// </summary>
        /// <param name="data">the data to look for</param>
        /// <param name="selectwhenfound">set to true to select the found item</param>
        public void FindTreeViewItem(IHierarchalData data, bool selectwhenfound)
        {
            _pendingSelect = data;
            _selectFoundItem = selectwhenfound;
            ContinueFind();
        }

        /// <summary>
        /// Creates a HierarchalTreeViewItem
        /// </summary>
        /// <returns>a HierarchalTreeViewItem</returns>
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new HierarchalTreeViewItem();
        }

        /// <summary>
        /// Returns true if the item is a HierarchalTreeViewItem
        /// </summary>
        /// <param name="item">the item to test</param>
        /// <returns>true or false</returns>
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is HierarchalTreeViewItem;
        }

        /// <summary>
        /// Preparses a data template for hierarchal data 
        /// </summary>
        /// <param name="element">the element</param>
        /// <param name="item">the item to add</param>
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            var hierarchicalDataTemplate = ItemTemplate as HierarchicalDataTemplate;
            var testdata = item as IHierarchalData;
            if (hierarchicalDataTemplate != null && testdata != null)
            {
                hierarchicalDataTemplate.ItemsSource = new Binding("Items");
                testdata.Populate();
            }

            base.PrepareContainerForItemOverride(element, item);
        }

        /// <summary>
        /// Gets a HierarchalTreeViewItem based on a IHierarchalData object - may be async
        /// </summary>
        /// <param name="data">The data to find</param>
        /// <param name="didExpand">if this value is true, </param>
        /// <returns>the treeview item it found</returns>
        private HierarchalTreeViewItem GetTreeViewItem(IHierarchalData data, ref bool didExpand)
        {
            if (data == null)
                return null;

            var tvitem = (HierarchalTreeViewItem)ItemContainerGenerator.ContainerFromItem(data);

            if (tvitem != null)
                return tvitem;

            tvitem = GetTreeViewItem(data.Parent, ref didExpand);

            if (tvitem == null)
                return null;

            didExpand = true;
            tvitem.IsExpanded = true;

            return (HierarchalTreeViewItem)tvitem.ItemContainerGenerator.ContainerFromItem(data);
        }

        private void Control_LayoutUpdated(object sender, EventArgs e)
        {
            if (_pendingSelect != null)
                ContinueFind();
        }

        private void ContinueFind()
        {
            if (ItemsSource == null)
                return;

            var didExpand = false;
            var tvitem = GetTreeViewItem(_pendingSelect, ref didExpand);

            if (tvitem != null || !didExpand)
            {
                if (_selectFoundItem && tvitem != null)
                    tvitem.IsSelected = true;

                var select = _pendingSelect;
                _pendingSelect = null;

                if (FindTreeVewItemComplete != null)
                    FindTreeVewItemComplete(this, tvitem, select);
            }
        }
    }
}
